/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.yokeyword.fragmentation;

import me.yokeyword.fragmentation.extensions.FractionManagerEx;
import me.yokeyword.fragmentation.queue.Action;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.multimodalinput.event.TouchEvent;

public class SupportAbilityDelegate {
    private ISupportAbility mSupport;
    private FractionManagerEx mFractionManagerEx;
    boolean mFractionClickable = true;

    private TransactionDelegate mTransactionDelegate;
    private int mDefaultFractionBackground = 0;

    public SupportAbilityDelegate(ISupportAbility support) {
        if (!(support instanceof FractionAbility))
            throw new RuntimeException("Must extends FractionAbility");
        this.mSupport = support;
        FractionAbility mAbility = (FractionAbility) support;
        mFractionManagerEx = new FractionManagerEx(mAbility.getFractionManager());
    }

    public void onStart() {
        mTransactionDelegate = getTransactionDelegate();
    }

    public TransactionDelegate getTransactionDelegate() {
        if (mTransactionDelegate == null) {
            mTransactionDelegate = new TransactionDelegate(mSupport);
        }
        return mTransactionDelegate;
    }

    /**
     * 当Fraction根布局 没有 设定background属性时,
     * 可以通过该方法改变Fraction背景。
     * @param backgroundRes set fraction background id
     */
    public void setDefaultFractionBackground(int backgroundRes) {
        mDefaultFractionBackground = backgroundRes;
    }

    public int getDefaultFractionBackground() {
        return mDefaultFractionBackground;
    }

    /**
     * Causes the Runnable r to be added to the action queue.
     * <p>
     * The runnable will be run after all the previous action has been run.
     * <p>
     * @param runnable new task to run in UI thread
     * 前面的事务全部执行后 执行该Action
     */
    public void post(final Runnable runnable) {
        mTransactionDelegate.post(runnable);
    }

    /**
     * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
     */
    public void onBackPressed() {
        mTransactionDelegate.mActionQueue.enqueue(new Action(Action.ACTION_BACK) {
            @Override
            public void run() {
                if (!mFractionClickable) {
                    mFractionClickable = true;
                }

                // 获取activeFraction:即从栈顶开始 状态为show的那个Fraction
                ISupportFraction activeFraction = SupportHelper.getActiveFraction(mFractionManagerEx);
                if (mTransactionDelegate.dispatchBackPressedEvent(activeFraction)) return;

                mSupport.onBackPressedSupport();
            }
        });
    }

    /**
     * 该方法回调时机为,Ability回退栈内Fraction的数量 小于等于1 时,默认finish Ability
     * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFraction内的onBackPressedSupport()回退事件正常执行
     */
    public void onBackPressedSupport() {
        if (mFractionManagerEx.getBackStackEntryCount() > 1) {
            pop();
        }
    }

    public boolean dispatchTouchEvent(TouchEvent ev) {
        // 防抖动(防止点击速度过快)
        return !mFractionClickable;
    }

    /**********************************************************************************************/

    /**
     * 加载根Fraction, 即Ability内的第一个Fraction 或 Fraction内的第一个子Fraction
     * @param toFraction new fraction to load
     * @param containerId resource id to inflate
     */
    public void loadRootFraction(int containerId, ISupportFraction toFraction) {
        loadRootFraction(containerId, toFraction, true, false);
    }

    public void loadRootFraction(int containerId, ISupportFraction toFraction, boolean addToBackStack, boolean allowAnimation) {
        mFractionManagerEx.checkNewRecordOrAdd((Fraction) toFraction);
        toFraction.getSupportDelegate().setFractionManagerEx(mFractionManagerEx);
        mTransactionDelegate.loadRootTransaction(mFractionManagerEx, containerId, toFraction, addToBackStack, allowAnimation);
    }

    /**
     * show一个Fraction,hide其他同栈所有Fraction
     * 使用该方法时，要确保同级栈内无多余的Fraction,(只有通过loadMultipleRootFraction()载入的Fraction)
     * <p>
     * 建议使用更明确的{@link #showHideFraction(ISupportFraction, ISupportFraction)}
     *
     * @param showFraction 需要show的Fraction
     */
    public void showHideFraction(ISupportFraction showFraction) {
        showHideFraction(showFraction, null);
    }

    /**
     * show一个Fraction,hide一个Fraction ; 主要用于类似微信主页那种 切换tab的情况
     *
     * @param showFraction 需要show的Fraction
     * @param hideFraction 需要hide的Fraction
     */
    public void showHideFraction(ISupportFraction showFraction, ISupportFraction hideFraction) {
        mTransactionDelegate.showHideFraction(mFractionManagerEx, showFraction, hideFraction);
    }

    public void start(ISupportFraction toFraction) {
        start(toFraction, ISupportFraction.LAUNCHMODE_STANDARD);
    }

    /** Start new fraction
     * @param launchMode Similar to Ability's LaunchMode.
     * @param toFraction new fraction
     */
    public void start(ISupportFraction toFraction, int launchMode) {
        mTransactionDelegate.dispatchStartTransaction(mFractionManagerEx, getTopFraction(), toFraction, 0, launchMode, TransactionDelegate.TYPE_ADD);
    }

    /**
     * Launch an fraction for which you would like a result when it poped.
     * @param toFraction new fraction
     * @param requestCode Task id
     */
    public void startForResult(ISupportFraction toFraction, int requestCode) {
        mTransactionDelegate.dispatchStartTransaction(mFractionManagerEx, getTopFraction(), toFraction, requestCode, ISupportFraction.LAUNCHMODE_STANDARD, TransactionDelegate.TYPE_ADD_RESULT);
    }

    /**
     * Start the target Fraction and pop itself
     * @param toFraction pop top fraction and start to fraction
     */
    public void startWithPop(ISupportFraction toFraction) {
        mTransactionDelegate.startWithPop(mFractionManagerEx, getTopFraction(), toFraction);
    }

    public void startWithPopTo(ISupportFraction toFraction, Class<?> targetFractionClass, boolean includeTargetFraction) {
        mTransactionDelegate.startWithPopTo(mFractionManagerEx, getTopFraction(), toFraction, targetFractionClass.getName(), includeTargetFraction);
    }

    public void replaceFraction(ISupportFraction toFraction, boolean addToBackStack) {
        mTransactionDelegate.dispatchStartTransaction(mFractionManagerEx, getTopFraction(), toFraction, 0, ISupportFraction.LAUNCHMODE_STANDARD, addToBackStack ? TransactionDelegate.TYPE_REPLACE : TransactionDelegate.TYPE_REPLACE_DONT_BACK);
    }

    /**
     * Pop the child fraction.
     */
    public void pop() {
        mTransactionDelegate.pop(mFractionManagerEx);
    }

    public FractionManagerEx getSupportFractionManagerEx() {
        return mFractionManagerEx;
    }

    private ISupportFraction getTopFraction() {
        return SupportHelper.getTopFraction(mFractionManagerEx);
    }
}
